package k8ssvc

import (
	"context"
	"deployment-service/k8s"
	"fmt"
	"io/ioutil"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	metrics "k8s.io/metrics/pkg/client/clientset/versioned"
	"os"
	"time"
)

type adapter struct {
	cfg           *rest.Config
	cfgStr       string
	clientSet     *kubernetes.Clientset
	ctx           context.Context
	dynamicClient dynamic.Interface
}

func (m *adapter) GetClientSet() (*kubernetes.Clientset, error) {
	if m.clientSet == nil {
		cfg, err := m.getConfig()
		if err != nil {
			return nil, err
		}

		m.clientSet, err = kubernetes.NewForConfig(cfg)
		if err != nil {
			return nil, err
		}
	}

	return m.clientSet, nil
}

func (m *adapter) GetDynamicClient() (dynamic.Interface, error) {
	if m.dynamicClient == nil {
		cfg, err := m.getConfig()
		if err != nil {
			return nil, err
		}

		m.dynamicClient, err = dynamic.NewForConfig(cfg)
		if err != nil {
			return nil, err
		}
	}

	return m.dynamicClient, nil
}

func (m *adapter) GetNamespace(name string) (k8s.IK8sNamespace, error) {
	cfg, err := m.getConfig()
	if err != nil {
		return nil, err
	}

	cs, err := m.GetClientSet()
	if err != nil {
		return nil, err
	}

	// 获取pod
	podClient := cs.CoreV1().Pods(name)
	// 获取deployment
	deploymentClient := cs.AppsV1().Deployments(name)
	return &namespaceAdapter{
		clientSet: cs,
		config:    cfg,
		ctx:       m.ctx,
		podClient: podClient,
		deploymentClient: deploymentClient,
	}, nil
}

func (m *adapter) write2File(cnt string) string  {
	now := time.Now().Nanosecond()
	fileName := fmt.Sprintf("%v", now)

	cntByte := []byte(cnt)
	ioutil.WriteFile(fileName, cntByte, 0666)
	return fileName
}
func (m *adapter) getConfig() (*rest.Config, error) {
	if m.cfg == nil {
		var err error

		var kubeconfigPath string

		// 保存cfgStr到本地
		kubeconfigPath = m.write2File(m.cfgStr)
		m.cfg, err = clientcmd.BuildConfigFromFlags(
			"",
			kubeconfigPath,
		)
		if err != nil {
			return nil, err
		}

		os.Remove(kubeconfigPath)
	}

	return m.cfg, nil
}

func (m *adapter) GetMetrics() (k8s.IK8sMetrics, error) {
	cfg, err := m.getConfig()
	if err != nil {
		return nil, err
	}

	mc, err := metrics.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	return &metricsAdapter{
		ctx: m.ctx,
		mc: mc,
		nodeMc: mc.MetricsV1beta1().NodeMetricses(),
	}, nil
}

// New is contract.IK8s实例
func New(cfgStr string) k8s.IK8s {
	return &adapter{
		cfgStr: cfgStr,
		ctx:     context.Background(),
	}
}